package com.android.tnovoselec.travelassistant.async;

import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.Callable;

import android.content.Context;
import android.util.Log;

import com.android.tnovoselec.travelassistant.Config;
import com.android.tnovoselec.travelassistant.dto.BankomatDto;
import com.android.tnovoselec.travelassistant.dto.BankomatiResultHolder;
import com.android.tnovoselec.travelassistant.dto.BenzinskaDto;
import com.android.tnovoselec.travelassistant.dto.BenzinskeResultHolder;
import com.google.android.maps.GeoPoint;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.nth.android.lbs.location.DistanceCalculator;

public class BenzinskeSearcher implements Callable<Boolean> {

	private static final double LONG_SCALE_DE_APPROX = Math.cos(Math.toRadians(50)); // 50
																						// latitude
	@SuppressWarnings("unused")
	private static final double LONG_SCALE_DE_APPROX_POW = Math.pow(BenzinskeSearcher.LONG_SCALE_DE_APPROX, 2);

	private final Context context;
	private final Dao<BenzinskaDto, String> benzinskeDao;
	private GeoPoint geoPoint;
	private String activeType;

	private final double latitude;
	private final double longitude;

	public BenzinskeSearcher(Context context, Dao<BenzinskaDto, String> benzinskeDao, GeoPoint geoPoint, String activeType) {
		super();
		this.context = context;
		this.benzinskeDao = benzinskeDao;
		this.geoPoint = geoPoint;
		this.activeType=activeType;

		if (geoPoint != null) {
			latitude = geoPoint.getLatitudeE6() / 1E6D;
			longitude = geoPoint.getLongitudeE6() / 1E6D;
		} else {
			latitude = Config.zgLat;
			longitude = Config.zgLng;
			this.geoPoint = new GeoPoint((int)(latitude*1e6), (int)(longitude*1e6));
		}
	}

	@Override
	public Boolean call() throws Exception {
		QueryBuilder<BenzinskaDto, String> queryBuilder = benzinskeDao.queryBuilder();
		queryBuilder.setWhere(getWhereQueryPart(queryBuilder));
		queryBuilder.orderByRaw(getOrderQueryPart());
		queryBuilder.limit(Integer.valueOf(Config.RESULT_LIMIT));

		PreparedQuery<BenzinskaDto> preparedQuery = queryBuilder.prepare();
		List<BenzinskaDto> benzinske = benzinskeDao.query(preparedQuery);
		Log.i("Kita", "Nadjeno: " + benzinske.size());
		BenzinskeResultHolder.filter(benzinske, geoPoint);
		if ((benzinske != null)) {
			BenzinskeResultHolder.init(benzinske, geoPoint, context);
			return Boolean.TRUE;
		}

		return Boolean.FALSE;
	}

	private Where<BenzinskaDto, String> getWhereQueryPart(QueryBuilder<BenzinskaDto, String> queryBuilder) throws SQLException {
		Where<BenzinskaDto, String> where = queryBuilder.where();

		// This is good enough, theoretically this is not perfect circle, but at
		// this range it is :-)!
		GeoPoint gpTop = DistanceCalculator.extrapolate(latitude, longitude, 0, Config.RESULT_DISTANCE_LIMIT);
		GeoPoint gpRight = DistanceCalculator.extrapolate(latitude, longitude, 90, Config.RESULT_DISTANCE_LIMIT);

		double tempLatitude = gpTop.getLatitudeE6() / 1E6D;
		double tempLongitude = gpRight.getLongitudeE6() / 1E6D;

		where.between(BankomatDto.LATITUDE, String.valueOf(latitude - (tempLatitude - latitude)), String.valueOf(tempLatitude));
		where.and();
		where.between(BankomatDto.LONGITUDE, String.valueOf(longitude - (tempLongitude - longitude)), String.valueOf(tempLongitude));
		where.and();
		where.like("bank_id", "%"+activeType+"%");

		return where;
	}

	/**
	 * Approximation - all points are in first quadrant.<br />
	 * This is just fast approximation (taking latitudes at the same level) -
	 * not real distance function but good and fast enough.<br />
	 * 1 mile in latitude != 1 mile in longitude, except at the equator!
	 */
	private String getOrderQueryPart() {
		double longitudeScale = Math.pow(Math.cos(Math.toRadians(latitude)), 2);

		return "(" + latitude + " - latitude) * (" + latitude + " - latitude) + " + longitudeScale + " * (" + longitude + " - longitude) * (" + longitude
				+ " - longitude) ASC";
	}

}
